﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ESRI.ArcGIS.DataSourcesFile;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.Geodatabase;
using FRS.FileProcessor;
using System.Collections;
using System.Configuration;

namespace FRS.EsriExtension
{
    /// <summary>
    /// @Author：https://blog.csdn.net/HerryDong
    /// @Address导入：https://blog.csdn.net/HerryDong/article/details/103330899?utm_source=app&app_version=4.13.0&code=app_1562916241&uLinkId=usr1mkqgl919blen
    /// @Address唯一值：https://blog.csdn.net/HerryDong/article/details/105664676?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162963273716780255234057%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162963273716780255234057&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v29_ecpm-1-105664676.first_rank_v2_pc_rank_v29&utm_term=ArcEngine+%E5%A4%9A%E4%B8%AAshp%EF%BC%8C%E5%B1%9E%E6%80%A7%EF%BC%8C%E6%8B%86%E5%88%86&spm=1018.2226.3001.4187
    /// </summary>
    public static class IFeatureClassExtension
    {
        #region 将point.shp文件导入test.gdb.ds中，并重命名为aaa的示例
        private static void Sample()
        {
            #region 设置属性过滤器
            IQueryFilter pQueryFilter = new QueryFilter();
            pQueryFilter.AddField("FID");
            pQueryFilter.WhereClause = "FID>=0 and FID<=4";
            #endregion
            #region 导入数据
            IFeatureClass pFeatureClass = GeoFileGetter.GetShapefile(@"C:\Users\DSF\Desktop\shp\point.shp");
            bool ok = pFeatureClass.ImportIntoGeodatabase(@"C:\Users\DSF\Desktop\test.gdb", "ds", "aaa", pQueryFilter);
            #endregion
            #region 提示用户信息
            if (ok)
            {
                System.Windows.Forms.MessageBox.Show("导入成功", "提示", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Asterisk);
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("导入失败", "提示", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
            }
            #endregion
        }
        #endregion

        /// <summary>
        /// 将要素类导入到指定的空间数据库中的某个特定的要素数据集中【Geodatabase.FeatureDataSet】
        /// <para>@Warning: 如果需要导入至特定的要素数据集，则需要保证导入的要素类用一致的空间参考信息，否则会导入空数据！</para>
        /// <para>@Warning: 保证目标gdb中不含有导入要素类的重命名，否则将会导入失败！</para>
        /// </summary>
        /// <param name="pSourceFeatureClass">源要素类【导入哪个shp文件】</param>
        /// <param name="gdbPath">指定的空间数据库位置【导入到哪个数据库】</param>
        /// <param name="targetDatasetName">目标要素数据集的名称【导入到哪个范围】[default=导入至gdb的根目录下]</param>
        /// <param name="targetFeatureClassName">目标要素类的名称【导入时重命名】[default=以导入要素类的名字命名]</param>
        /// <param name="pQueryFilter">需要的筛选命令[default=导入全部要素]</param>
        /// <returns>如果导入成功返回TRUE，否则返回FALSE</returns>
        public static bool ImportIntoGeodatabase(this IFeatureClass pSourceFeatureClass, string gdbPath, string targetDatasetName = null, string targetFeatureClassName = null, IQueryFilter pQueryFilter = null)
        {
            #region 源数据工作空间（SHP）
            IDataset pSourceDataset = pSourceFeatureClass as IDataset;
            IFeatureClassName pSourceFeatureClassName = pSourceDataset.FullName as IFeatureClassName;
            IWorkspace pSourceWorkspace = pSourceDataset.Workspace;
            #endregion
            #region 目标数据工作空间（GDB）
            IWorkspaceFactory pTargetWorkspaceFactory = new FileGDBWorkspaceFactory();
            IWorkspace pTargetWorkspace = pTargetWorkspaceFactory.OpenFromFile(gdbPath, 0);
            IFeatureWorkspace pTargetFeatureWorkspace = pTargetWorkspace as IFeatureWorkspace;
            #endregion
            #region 若要素数据集名称不为空，则获取该数据集，默认放在Geodatabase的“根目录”下
            IFeatureDatasetName pTargetFeatureDatasetName = null;
            if (!(string.IsNullOrWhiteSpace(targetDatasetName)))
            {
                pTargetFeatureDatasetName = pTargetFeatureWorkspace.OpenFeatureDataset(targetDatasetName).FullName as IFeatureDatasetName;
            }
            #endregion
            #region 设置目标数据属性
            IDataset pTargetDataSet = pTargetWorkspace as IDataset;
            IWorkspaceName pTargetWorkspaceName = pTargetDataSet.FullName as IWorkspaceName;
            IFeatureClassName pTargetFeatureClassName = new FeatureClassName() as IFeatureClassName;
            IDatasetName pTargetDatasetName = pTargetFeatureClassName as IDatasetName;
            pTargetDatasetName.WorkspaceName = pTargetWorkspaceName;
            pTargetDatasetName.Name = (string.IsNullOrWhiteSpace(targetFeatureClassName) ? pSourceFeatureClass.AliasName : targetFeatureClassName);
            #endregion
            #region 检查字段并进行转换
            IFieldChecker pFieldChecker = new FieldChecker();
            pFieldChecker.InputWorkspace = pSourceWorkspace;
            pFieldChecker.ValidateWorkspace = pTargetWorkspace;

            IFields pSourceFields = pSourceFeatureClass.Fields;
            IFields pTargetFields = null;
            IEnumFieldError pEnumFieldError = null;
            pFieldChecker.Validate(pSourceFields, out pEnumFieldError, out pTargetFields);
            #endregion
            #region 数据转换
            IFeatureDataConverter pFeatureDataConverter = new FeatureDataConverter();
            try
            {
                pFeatureDataConverter.ConvertFeatureClass(pSourceFeatureClassName, pQueryFilter, pTargetFeatureDatasetName, pTargetFeatureClassName, null, pTargetFields, "", 1000, 0);
                return true;
            }
            catch (Exception ex)
            {
                ExceptionLog.ExceptionLogRecorder.WriteExceptionLog(ex, pSourceFeatureClass.AliasName + "导入Geodatabase：" + gdbPath + "失败\n可能该数据库中含有同名要素类");
                return false;
            }
            #endregion
        }
        /// <summary>
        /// 获取唯一值
        /// </summary>
        /// <param name="pFeatureClass">对哪一个要素类进行获取</param>
        /// <param name="fieldName">对哪一个字段进行获取</param>
        /// <returns>所有的唯一值</returns>
        public static List<string> GetUniqueValue(this IFeatureClass pFeatureClass, string fieldName)
        {
            // 创建一个查询过滤器
            IQueryFilter pQueryFilter = new QueryFilter();
            pQueryFilter.AddField(fieldName);
            // 要素游标
            IFeatureCursor pFeatureCursor = pFeatureClass.Search(pQueryFilter, true);
            ICursor pCursor = pFeatureCursor as ICursor;
            // 设置统计信息
            IDataStatistics pDataStatistics = new DataStatistics();
            pDataStatistics.Field = fieldName;
            pDataStatistics.Cursor = pCursor;
            // 获取唯一值
            IEnumerator uniqueValues = pDataStatistics.UniqueValues;
            uniqueValues.Reset();
            // 使用IField接口获取当前所需要使用的字段的信息
            IFields fields = pFeatureClass.Fields;
            IField field = fields.get_Field(fields.FindField(fieldName));
            // 遍历唯一值
            List<string> list = new List<string>();
            while (uniqueValues.MoveNext())
            {
                string value = uniqueValues.Current.ToString();
                if (field.Type == esriFieldType.esriFieldTypeString)
                {
                    list.Add("\'" + value + "\'");
                }
                else
                {
                    list.Add(value);
                }
            }
            return list;
        }
        /// <summary>
        /// 将查询过滤器中的要素类另存为shpfile文件
        /// </summary>
        /// <param name="pSourceFeatureClass">要素类【对象】</param>
        /// <param name="targetShpfilePath">目标Shp文件路径【默认全部另存为】</param>
        /// <param name="pQueryFilter">查询过滤器【依据】</param>
        public static bool SaveAsShpfile(this IFeatureClass pSourceFeatureClass, string targetShpfilePath, IQueryFilter pQueryFilter = null)
        {
            // 源数据工作空间
            IDataset pSourceDataset = pSourceFeatureClass as IDataset;
            IFeatureClassName pSourceFeatureClassName = pSourceDataset.FullName as IFeatureClassName;
            IWorkspace pSourceWorkspace = pSourceDataset.Workspace;

            // 目标数据工作空间
            IWorkspaceFactory pTargetWorkspaceFactory = new ShapefileWorkspaceFactory();
            IWorkspace pTargetWorkspace = pTargetWorkspaceFactory.OpenFromFile(System.IO.Path.GetDirectoryName(targetShpfilePath), 0);
            IDataset pTargetDataSet = pTargetWorkspace as IDataset;

            // 设置目标数据属性
            IWorkspaceName pTargetWorkspaceName = pTargetDataSet.FullName as IWorkspaceName;
            IFeatureClassName pTargetFeatureClassName = new FeatureClassName() as IFeatureClassName;
            IDatasetName pTargetDatasetName = pTargetFeatureClassName as IDatasetName;
            pTargetDatasetName.WorkspaceName = pTargetWorkspaceName;
            pTargetDatasetName.Name = System.IO.Path.GetFileName(targetShpfilePath);

            // 检查字段
            IFieldChecker pFieldChecker = new FieldChecker();
            pFieldChecker.InputWorkspace = pSourceWorkspace;
            pFieldChecker.ValidateWorkspace = pTargetWorkspace;

            // 字段转换
            IFields pSourceFields = pSourceFeatureClass.Fields;
            IFields pTargetFields = null;
            IEnumFieldError pEnumFieldError = null;
            pFieldChecker.Validate(pSourceFields, out pEnumFieldError, out pTargetFields);

            // 数据转换
            IFeatureDataConverter pFeatureDataConverter = new FeatureDataConverter();
            try
            {
                pFeatureDataConverter.ConvertFeatureClass(pSourceFeatureClassName, pQueryFilter, null, pTargetFeatureClassName, null, pTargetFields, "", 1000, 0);
                return true;
            }
            catch (Exception ex)
            {
                ExceptionLog.ExceptionLogRecorder.WriteExceptionLog(ex, string.Format("“{0}”另存为Shpfile文件：“{1}”失败！", pSourceFeatureClass.AliasName, targetShpfilePath));
                return false;
            }
        }
        /// <summary>
        /// 根据属性唯一值将要素类拆分成多个shp文件【默认输出目录：FeatureClassSplitIntoShpFileByAttribute_TargetDirectoryPath】
        /// </summary>
        /// <param name="pFeatureClass">被拆分的要素类</param>
        /// <param name="fieldName">依据哪个字段</param>
        /// <returns>是否成功拆分</returns>
        public static bool SplitByAttribute(this IFeatureClass pFeatureClass, string fieldName)
        {
            string targetDirectoryPath = ConfigurationManager.AppSettings["FeatureClassSplitIntoShpFileByAttribute_TargetDirectoryPath"];
            List<string> uniqueValues = pFeatureClass.GetUniqueValue(fieldName);
            foreach (string value in uniqueValues)
            {
                IQueryFilter pQueryFilter = new QueryFilter();
                pQueryFilter.WhereClause = string.Format("{0} = {1}", fieldName, value);
                if (!pFeatureClass.SaveAsShpfile(string.Format(@"{0}\{1}.shp", targetDirectoryPath, value), pQueryFilter))
                {
                    return false;
                }
            }
            return true;
        }
    }
}
